class GuaCanvas extends GuaObject {
  constructor(selector) {
    super();
    var canvas = _e(selector);
    this.canvas = canvas;
    this.context = canvas.getContext("2d");
    this.w = canvas.width;
    this.h = canvas.height;
    this.pixels = this.context.getImageData(0, 0, this.w, this.h);
    this.bytesPerPixel = 4;
    this.data = null;
    this.penColor = GuaColor.black();
  }
  render() {
    // 执行这个函数后, 才会实际地把图像画出来
    // ES6 新语法, 取出想要的属性并赋值给变量, 不懂自己搜「ES6 新语法」
    let { pixels, context } = this;
    context.putImageData(pixels, 0, 0);
  }
  _setPixel(x, y, color) {
    // color: GuaColor
    // 这个函数用来设置像素点, _ 开头表示这是一个内部函数, 这是我们的约定
    // 浮点转 int
    let int = Math.floor;
    x = int(x);
    y = int(y);
    // 用座标算像素下标
    let i = (y * this.w + x) * this.bytesPerPixel;
    // 设置像素
    let p = this.pixels.data;
    let { r, g, b, a } = color;
    // 一个像素 4 字节, 分别表示 r g b a
    p[i] = r;
    p[i + 1] = g;
    p[i + 2] = b;
    p[i + 3] = a;
  }
  drawPoint(point, color = GuaColor.black()) {
    let { w, h } = this;
    let p = point;
    if (p.x >= 0 && p.x <= w) {
      if (p.y >= 0 && p.y <= h) {
        this._setPixel(p.x, p.y, color);
      }
    }
  }
  drawScanline(v1, v2) {
    // v1 v2 是 y 相等的 2 个 GuaVertex
    // 画有颜色的直线
    let [a, b] = [v1, v2].sort((a, b) => a.position.x - b.position.x);
    // 将 v1 和 v2 按照 x 坐标进行排序，较小的为 a，较大的为 b

    let x1 = int(a.position.x);
    let x2 = int(b.position.x);
    let y = int(a.position.y);
    // 获取排序后 a 和 b 的 x 坐标，并获取 y 坐标

    var sign = x2 > x1 ? 1 : -1;
    // 确定线段的方向，1 表示从左到右，-1 表示从右到左

    let factor = 0;
    // 初始化插值因子

    for (var i = x1; i <= x2 + sign * 1; i += sign) {
      // 遍历 x 坐标范围，sign * 1 用于确保能够遍历到结束位置

      if (x1 != x2) {
        factor = (i - x1) / (x2 - x1);
        // 计算当前像素在线段上的相对位置，用于插值
      }

      var color = interpolate(a.color, b.color, factor);
      // 通过插值获取当前像素的颜色

      var vector = GuaVector.new(i, y);
      // 创建表示当前像素位置的向量

      this.drawPoint(vector, color);
      // 在当前像素位置绘制点，使用插值得到的颜色
    }

    this.render();
    // 渲染整个画布，显示更新后的图像
  }

  //   drawTriangle(v1, v2, v3) {
  //     // v1 v2 v3 都是 GuaVertex
  //     // 作为三角形的 3 个顶点
  //     let [a, b, c] = [v1, v2, v3].sort((a, b) => a.position.y - b.position.y);
  //     // 将 v1、v2、v3 按照 y 坐标进行排序，较小的为 a，较大的为 b，中间的为 c

  //     let middle_factor = 0;
  //     if (c.position.y - a.position.y != 0) {
  //       middle_factor =
  //         (b.position.y - a.position.y) / (c.position.y - a.position.y);
  //     }
  //     // 计算中间点的插值因子

  //     let middle = interpolate(a, c, middle_factor);
  //     // 计算中间点的位置

  //     let start_y = int(a.position.y);
  //     let end_y = int(b.position.y);
  //     // 计算扫描线的起始和结束位置

  //     for (var i = start_y; i < end_y + 1; i++) {
  //       let factor = 0;
  //       if (end_y != start_y) {
  //         factor = (i - start_y) / (end_y - start_y);
  //       } else {
  //         factor = 0;
  //       }
  //       let va = interpolate(a, b, factor);
  //       let vb = interpolate(a, middle, factor);
  //       this.drawScanline(va, vb);
  //     }
  //     // 绘制三角形的上半部分扫描线

  //     start_y = int(b.position.y);
  //     end_y = int(c.position.y);
  //     // 计算下半部分扫描线的起始和结束位置

  //     for (var j = start_y; j < end_y + 1; j++) {
  //       let factor = 0;
  //       // 计算插值因子
  //       if (end_y != start_y) {
  //         factor = (j - start_y) / (end_y - start_y);
  //       } else {
  //         factor = 0;
  //       }
  //       let va = interpolate(b, c, factor);
  //       let vb = interpolate(middle, c, factor);
  //       // 计算两个端点的插值

  //       this.drawScanline(va, vb);
  //     }
  //     // 绘制三角形的下半部分扫描线

  //     this.render();
  //     // 渲染整个画布，显示更新后的图像
  //   }
  // 绘制三角形的函数，参数为三个顶点 v1、v2、v3
  drawTriangle(v1, v2, v3) {
    // 将三个顶点按照 y 坐标升序排列，得到排序后的三个点 a、b、c
    let [a, b, c] = [v1, v2, v3].sort((a, b) => a.position.y - b.position.y);

    // 计算中间点的插值因子，确保不会除以零
    let middle_factor = 0;
    if (c.position.y - a.position.y !== 0) {
      middle_factor =
        (b.position.y - a.position.y) / (c.position.y - a.position.y);
    }

    // 计算中间点的位置
    let middle = interpolate(a, c, middle_factor);

    // 计算上半部分扫描线的起始和结束位置
    let start_y = Math.floor(a.position.y);
    let end_y = Math.floor(b.position.y);

    // 遍历上半部分扫描线
    for (let i = start_y; i < end_y + 1; i++) {
      // 计算插值因子
      let factor = end_y !== start_y ? (i - start_y) / (end_y - start_y) : 0;

      // 计算两个端点的插值
      let va = interpolate(a, b, factor);
      let vb = interpolate(a, middle, factor);

      // 调用绘制扫描线的函数
      this.drawScanline(va, vb);
    }

    // 计算下半部分扫描线的起始和结束位置
    start_y = Math.floor(b.position.y);
    end_y = Math.floor(c.position.y);

    // 遍历下半部分扫描线
    for (let j = start_y; j < end_y + 1; j++) {
      // 计算插值因子
      let factor = end_y !== start_y ? (j - start_y) / (end_y - start_y) : 0;

      // 计算两个端点的插值
      let va = interpolate(b, c, factor);
      let vb = interpolate(middle, c, factor);

      // 调用绘制扫描线的函数
      this.drawScanline(va, vb);
    }

    // 渲染整个画布，显示更新后的图像
    this.render();
  }
}
